home *** CD-ROM | disk | FTP | other *** search
/ Garbo / Garbo.cdr / mac / comm / revrdist.sit / RevRdist / RevRdist src / match.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-08-09  |  23.3 KB  |  927 lines  |  [TEXT/KAHL]

  1. /*
  2.  * match.c - routines for synchronizing client and server folders,
  3.  *    based on the configuration file
  4.  */
  5.  
  6. #include "RevRdist.h"
  7. #include "dispatch.h"
  8. #include <nAppleTalk.h>
  9. #include <TransSkelProto.h>
  10. #include <TransDisplayProto.h>
  11.  
  12. /*
  13.  * define some bit pattern mnemonics indicating where a file/folder
  14.  * name appears
  15.  */
  16.  
  17. #define    xxD            1                /* entry is in control file tree */
  18. #define xSx            2                /* entry is in server catalog */
  19. #define Cxx            4                /* entry is in client catalog */
  20. #define    xSD            (xSx|xxD)        /* and various combinations */
  21. #define CxD            (Cxx|xxD)
  22. #define CSx            (Cxx|xSx)
  23. #define    CSD            (Cxx|xSx|xxD)
  24.  
  25. /*
  26.  * prototypes for local routines
  27.  */
  28. static tnode_t * checkTypes (dnode_t *, cnode_t *);
  29. static short    least (StringPtr, StringPtr, StringPtr);
  30. static void        mergeActions (actions_t *, actions_t *, actions_t *);
  31. static void        updateFInfo (cnode_t *, cnode_t *, short,
  32.                         action_t, action_t, action_t);
  33.  
  34.  
  35. /*
  36.  *=========================================================================
  37.  * matchFolder - synchronize one folder given in the control file tree
  38.  * entry:    first arg = ptr to dnode_t of folder to work on
  39.  *            second arg = ptr to default actions to apply
  40.  *            third arg = ptr to server dirID of folder equivalent to first arg
  41.  *            fourth arg = ptr to client dirID of ditto
  42.  *            fifth arg = ptr to boolean true if within junk folder
  43.  *=========================================================================
  44.  */
  45. DISPATCHED (matchFolder)
  46. {
  47.     struct lm                        /* local memory */
  48.     {
  49.         frame_t            f;            /* basic dispatch frame */
  50.         cnode_t *        clientp;    /* current client entry */
  51.         cnode_t *        serverp;    /* current server entry */
  52.         dnode_t *        distp;        /* current control file entry */
  53.         dnode_t *        dt;            /* copy of first arg */
  54.         cnode_t *        ct;            /* client catalog tree */
  55.         cnode_t *        st;            /* server catalog tree */
  56.         Longint            cd;            /* copy of fourth arg */
  57.         Longint            sd;            /* copy of third arg */
  58.         action_t        todo;        /* choice for multi-state actions */
  59.         cnode_t            tcn;        /* dummy client catalog entry */
  60.         dnode_t            tdn;        /* dummy control file entry */
  61.         cnode_t            tsn;        /* dummy server catalog entry */
  62.         StringPtr        name;        /* folder name */
  63.         actions_t        da;            /* default actions for folder */
  64.         Boolean            ij;            /* true if within junk folder */
  65.     };
  66.     typedef struct lm    lm_t;
  67.     register lm_t *        m;
  68.     
  69.     struct actions        ca;            /* current actions */
  70. register cnode_t *        clientp;    /* copy of lm.clientp */
  71.     StringPtr            cname;        /* client entry name */
  72.     ctype_t                ctype;        /* entry for file or folder */
  73.     dnode_t *            distp;        /* copy of lm.distp */
  74.     StringPtr            dname;        /* control file entry name */
  75.     OSErr                error;
  76.     action_t            forcedIC;    /* forced "ifClient" action */
  77.     int                    len;        /* string length temp */
  78.     StringPtr            name;        /* name of current entry */
  79.     Ptr                    paramv[5];    /* param for called dispatch routines */
  80.     short                result;        /* our return value */
  81.     cnode_t *            serverp;    /* copy of lm.serverp */
  82.     StringPtr            sname;        /* server entry name */
  83.     Longint                temp;        /* temp dir ID */
  84.     action_t            todo;        /* action to perform */
  85.     tnode_t *            tp;            /* ptr to type_node matching file */
  86.     short                whereisit;    /* bits set per location of file/folder */
  87.     short                wherereal;    /* original copy of whereisit */
  88.  
  89.     error = 0;
  90.     result = request;
  91.     m = *(lm_t **)fh;
  92.     switch (request)
  93.     {
  94.     case R_INIT:
  95.         if (error = resizeFrame (fh, sizeof (lm_t)))
  96.             return R_ERROR;
  97.         m = *(lm_t **)fh;
  98.         m->dt = (dnode_t *)argv[0];
  99.         m->da = *((actions_t *)argv[1]);
  100.         m->sd = *(Longint *)argv[2];
  101.         m->cd = *(Longint *)argv[3];
  102.         m->ij = *(Boolean *)argv[4];
  103.         m->name = m->dt ? m->dt->name : (SP) "\p<unknown>";
  104.         m->f.state = 1;
  105.         return R_CONT;
  106.     
  107.     case R_BACKOUT:
  108.     case R_QUIT:
  109.         goto cleanexit;
  110.  
  111.     case R_CONT:
  112.         /*
  113.          * We handle only the first state here, in order to avoid nesting
  114.          * switches to an ugly depth.
  115.          * Build catalogs of the client and server folders.
  116.          */
  117.         if (m->f.state == 1)
  118.         {
  119.             if (Flags & DB_VERBOSE)
  120.                 notice (L_STARTF, m->name, nil);
  121.             if (m->cd)
  122.             {
  123.                 if ((m->ct = m->clientp = listFolder (ClientVol, m->cd)) == nil)
  124.                 {
  125.                     if (ClueID)
  126.                     {
  127.                         panic (false, E_SYS, nil);
  128.                         return R_BACKOUT;
  129.                     }
  130.                 }
  131.                 /*
  132.                  * Sense if we are starting on the junk folder
  133.                  */
  134.                 if (m->cd == File_list[FL_JUNK].f_info.dirID)
  135.                     m->ij = true;
  136.             }
  137.             if (m->sd)
  138.             {
  139.                 if ((m->st = m->serverp = listFolder (ServerVol, m->sd)) == nil)
  140.                 {
  141.                     if (ClueID == afpAccessDenied)
  142.                     {
  143.                         notice (L_ACCESS, m->name, nil);
  144.                     }
  145.                     else if (ClueID)
  146.                     {
  147.                         panic (false, E_SYS, nil);
  148.                         return R_BACKOUT;
  149.                     }
  150.                 }
  151.             }
  152.             if (m->dt && m->dt->childp)
  153.                 m->distp = m->dt->childp->sibp;
  154.             m->f.state = 2;
  155.             return result;
  156.         }
  157.         break;
  158.  
  159.     default:
  160.         return ( popCall (R_QUIT, nil) );    /* should not happen */
  161.     }
  162.     
  163.     /*
  164.      * Here is the bulk of the R_CONT code
  165.      * Note that if an action requires dispatching, this code is
  166.      * executed for each state.
  167.      */
  168.     clientp = m->clientp;
  169.     serverp = m->serverp;
  170.     distp = m->distp;
  171.     /*
  172.      * We are done when we reach the end of each of the three lists
  173.      */
  174.     if (!clientp && !serverp && !distp)
  175.     {
  176.         if (Flags & DB_VERBOSE)
  177.             notice (L_ENDF, m->name, nil);
  178.         else
  179.             statMsgClr ();
  180.         goto cleanexit;
  181.     }
  182.     /*
  183.      * Determine the next item to work on
  184.      */
  185.     cname = clientp ? clientp->name : HighValue;
  186.     sname = serverp ? serverp->name : HighValue;
  187.     dname = distp    ? distp->name    : HighValue;
  188.     wherereal = whereisit = least (cname, sname, dname);
  189.     if ((whereisit & xxD) && distp->altname)
  190.     {
  191.         /*
  192.          * If the file has an alternate name, use it after checking that
  193.          * the alternate file exists.
  194.          */
  195.         serverp = &m->tsn;
  196.         if (m->f.state == 2)
  197.         {
  198.             ZEROAT (serverp);
  199.             if (getInfo (distp->altname, ServerVol, m->sd, serverp))
  200.                 serverp->dirID = 0;    /* if altname doesn't exist */
  201.         }
  202.         if (serverp->dirID)
  203.             whereisit |= xSx;
  204.         else
  205.         {
  206.             whereisit &= ~xSx;
  207.             serverp = nil;
  208.         }
  209.     }
  210.     /*
  211.      * Select action list from control file entry if it exists,
  212.      * else from the defaults for this folder
  213.      */
  214.     if (whereisit & xxD)
  215.         mergeActions (&m->da, &distp->actions, &ca);
  216.     else
  217.         ca = m->da;
  218.     /*
  219.      * It might fall out that the client has the right name, but it is
  220.      * a file instead of a folder or vice versa.  Handle this by working
  221.      * with the client copy this pass and leaving the other copy for
  222.      * the next pass (forcing junking or discarding of the client copy).
  223.      */
  224.     forcedIC = 0;
  225.     if ((whereisit & CSx) == CSx && clientp->ctype != serverp->ctype)
  226.     {
  227.         whereisit &= ~xSD;
  228.         wherereal &= ~xSD;
  229.         if (ca.ifclient != A_DISCARD && ca.ifserver == A_UPDATE)
  230.             forcedIC = A_JUNK;
  231.     }
  232.     if ((whereisit & CxD) == CxD && (dtype_t) clientp->ctype != distp->d_type)
  233.     {
  234.         whereisit &= ~xxD;
  235.         wherereal &= ~xxD;
  236.         if (ca.ifclient != A_DISCARD && ca.ifserver == A_UPDATE)
  237.             forcedIC = A_JUNK;
  238.     }
  239.     /*
  240.      * In a similar fashion, if a file exists on both client and server,
  241.      * but has a different type or creator, treat the files separately.
  242.      */
  243.     if ((whereisit & CSx) == CSx && clientp->ctype == C_FILE)
  244.         if (clientp->in.f.finfo.fdType != serverp->in.f.finfo.fdType
  245.          || clientp->in.f.finfo.fdCreator != serverp->in.f.finfo.fdCreator)
  246.         {
  247.             whereisit &= ~xSD;
  248.             wherereal &= ~xSD;
  249.             if (ca.ifclient != A_DISCARD && ca.ifserver == A_UPDATE)
  250.                 forcedIC = A_JUNK;
  251.         }
  252.     /*
  253.      * We know where the next file/folder is.  Fetch its name and type.
  254.      */
  255.     if (whereisit & xxD)
  256.     {
  257.         ctype = (ctype_t) distp->d_type;
  258.         name = distp->name;
  259.     }
  260.     else if (whereisit & xSx)
  261.     {
  262.         ctype = serverp->ctype;
  263.         name = serverp->name;
  264.         if (m->f.state <= 2 && ctype == C_FILE
  265.         && (tp = checkTypes (m->dt, serverp)))
  266.             mergeActions (&ca, &tp->actions, &ca);
  267.     }
  268.     else if (whereisit & Cxx)
  269.     {
  270.         ctype = clientp->ctype;
  271.         name = clientp->name;
  272.         if (m->f.state <= 2 && ctype == C_FILE
  273.         && (tp = checkTypes (m->dt, clientp)))
  274.             mergeActions (&ca, &tp->actions, &ca);
  275.     }
  276.     else
  277.     {
  278.         /*
  279.          * Should not happen
  280.          */
  281.         ctype = C_FILE;
  282.         name = (SP) "\p<cannot happen>";
  283.     }
  284.     if (forcedIC)
  285.         ca.ifclient = forcedIC;
  286.     /*
  287.      * figure out what to do with the file/folder
  288.      */
  289.     if (m->f.state > 2)
  290.         todo = m->todo;
  291.     else
  292.     {
  293.         todo = ca.otherwise;
  294.         switch (whereisit)
  295.         {
  296.         case xxD:    /* in control file only */
  297.             todo = ca.otherwise;
  298.             break;
  299.     
  300.         case xSx:    /* on server, but not client */
  301.         case xSD:
  302.             todo = ca.ifserver;
  303.             if (todo == A_PASS)
  304.                 todo = ca.otherwise;
  305.             break;
  306.     
  307.         case Cxx:    /* on client, but not server */
  308.         case CxD:
  309.             todo = ca.ifclient;
  310.             if (todo == A_PASS)
  311.                 todo = ca.otherwise;
  312.             break;
  313.     
  314.         case CSx:    /* on both client and server */
  315.         case CSD:
  316.             if (ctype == C_FOLDER)
  317.                 break;
  318.             if (serverp->crDate != clientp->crDate && ca.ifcreate != A_PASS)
  319.             {
  320.                 todo = ca.ifcreate;
  321.                 break;
  322.             }
  323.             if (serverp->mdDate > clientp->mdDate && ca.ifnewer != A_PASS)
  324.             {
  325.                 todo = ca.ifnewer;
  326.                 break;
  327.             }
  328.             if (serverp->mdDate < clientp->mdDate && ca.ifolder != A_PASS)
  329.             {
  330.                 todo = ca.ifolder;
  331.                 break;
  332.             }
  333.             if ((serverp->in.f.fileLen != clientp->in.f.fileLen
  334.               || serverp->in.f.rsrcLen != clientp->in.f.rsrcLen)
  335.               && ca.ifsize != A_PASS)
  336.             {
  337.                  todo = ca.ifsize;
  338.                 break;
  339.             }
  340.             if (whereisit & xxD)
  341.                 todo = ca.otherwise;
  342.             else
  343.                 todo = A_IGNORE;
  344.             break;
  345.     
  346.         default:
  347.             todo = A_IGNORE;            /* should not happen */
  348.         }
  349.     }
  350.     if (ctype == C_FOLDER)
  351.     {
  352.         /*
  353.          * For a folder, E- means to use the S action instead.
  354.          */
  355.         if (todo == A_PASS)
  356.             todo = ca.ifserver;
  357.     }
  358.     /*
  359.      * Now that we know what to do, do it
  360.      */
  361.     switch (todo)
  362.     {
  363.     case A_IGNORE:
  364.         if ((Flags & DB_VERBOSE) && whereisit == xxD && ca.ifserver == A_UPDATE)
  365.             notice (L_MISSING, name, nil);
  366.     case A_PASS:
  367.         if (Flags & DB_VERBOSE)
  368.             notice (L_IGNORE, name, nil);
  369.         todo = A_IGNORE;
  370.         break;
  371.  
  372.     case A_JUNK:
  373.         if (!(whereisit & Cxx))
  374.             break;                    /* if it's not on the client, who cares */
  375.         if (m->ij)
  376.             break;                    /* cannot move to junk if already in junk */
  377.         error = moveToJunk (clientp);
  378.         if (error != dupFNErr)
  379.             break;
  380.         notice (L_TOOMANYJ, name, nil);
  381.         todo = A_DISCARD;
  382.         /* fall into ... */
  383.  
  384.     case A_DISCARD:
  385.         if (!(whereisit & Cxx))
  386.             break;                    /* if not on client, can't discard */
  387.         if (ctype == C_FILE)
  388.         {
  389.             error = discard (clientp, true);    /* discard a file */
  390.             break;
  391.         }
  392.         /*
  393.          * Since emptying a folder can take a while, we run it under the
  394.          * dispatcher.
  395.          */
  396.         if (clientp->dirID == File_list[FL_JUNK].f_info.dirID)
  397.             break;                        /* leave the junk folder alone */
  398.         switch (m->f.state)
  399.         {
  400.         case 2:
  401.             paramv[0] = (Ptr) clientp;
  402.             paramv[1] = nil;
  403.             m->f.state = 3;
  404.             m->todo = todo;
  405.             result = pushCall (emptyFolder, paramv);
  406.             if (result != R_CONT)
  407.                 m->f.state = 2;
  408.             else
  409.                 Depth++;
  410.             return result;
  411.         case 3:
  412.             /*
  413.              * After the folder is emptied, we can discard it
  414.              */
  415.             Depth--;
  416.             if (argv[0] == 0)
  417.                 error = discard (clientp, true);
  418.             m->f.state = 2;
  419.         }
  420.         break;
  421.  
  422.     case A_UPDATE:
  423.         if (!(whereisit & xSx))
  424.         {
  425.             /*
  426.              * The junk folder often has nested folders, which do not
  427.              * appear on the server.  Do not count this as an error.
  428.              * For any other situation, warn if the update target does
  429.              * not exist on the server.
  430.              */
  431.             if (ctype == C_FILE || !(m->ij))
  432.             {
  433.                 notice (L_MISSING, name, nil);
  434.                 todo = A_IGNORE;
  435.                 break;
  436.             }
  437.         }
  438.         /*
  439.          * If we are updating a file, use copyFile.
  440.          * To update a folder, use ourselves.
  441.          */
  442.         if (ctype == C_FILE)
  443.         {
  444.             switch (m->f.state)
  445.             {
  446.             case 2:
  447.                 if (!(whereisit & Cxx))
  448.                 {
  449.                     /*
  450.                      * If file not already on client, build a dummy catalog
  451.                      * entry for it
  452.                      */
  453.                     clientp = &m->tcn;
  454.                     ZEROAT (clientp);
  455.                     clientp->ctype = ctype;
  456.                     clientp->parID = m->cd;
  457.                     COPYPS (name, clientp->name);
  458.                 }
  459.                 paramv[0] = (Ptr) serverp;
  460.                 paramv[1] = (Ptr) clientp;
  461.                 paramv[2] = (Ptr) m->name;
  462.                 m->f.state = 3;
  463.                 m->todo = todo;
  464.                 result = pushCall (copyFile, paramv);
  465.                 if (result != R_CONT)
  466.                     m->f.state = 2;
  467.                 return result;
  468.  
  469.             case 3:
  470.                 m->f.state = 2;
  471.                 if (!(whereisit & Cxx))
  472.                 {
  473.                     clientp = &m->tcn;
  474.                     whereisit |= Cxx;
  475.                 }
  476.             }
  477.             break;
  478.         }
  479.         /*
  480.          * Here for folder update
  481.          */
  482.         switch (m->f.state)
  483.         {
  484.         case 2:
  485.             /*
  486.              * If the folder is not in the control list, use the dummy
  487.              * dnode to describe it while it is being updated.
  488.              */
  489.             if (! (whereisit & xxD) )
  490.             {
  491.                 distp = &m->tdn;
  492.                 ZEROAT (distp);
  493.                 COPYPS (name, distp->name);
  494.                 if (m->dt)                /* propagate type list */
  495.                     distp->tlistp = m->dt->tlistp;
  496.             }
  497.             else
  498.                 if (distp && distp->childp)
  499.                     mergeActions (&m->da, &distp->childp->actions, &ca);
  500.             /*
  501.              * If the folder does not exist yet on client, create it.
  502.              */
  503.             if (! (whereisit & Cxx))
  504.             {
  505.                 clientp = &m->tcn;
  506.                 if (Flags & DB_LISTONLY)
  507.                 {
  508.                     notice (L_WCREATE, name, nil);
  509.                     ZEROAT (clientp);
  510.                     clientp->ctype = ctype;
  511.                 }
  512.                 else
  513.                 {
  514.                     error = createFolder (name, ClientVol, m->cd, serverp);
  515.                     if (error == 0)
  516.                         error = getInfo (name, ClientVol, m->cd, clientp);
  517.                     if (error)
  518.                     {
  519.                         warning (E_SYS, nil);
  520.                         error = 0;
  521.                         break;
  522.                     }
  523.                 }
  524.                 whereisit |= Cxx;
  525.             }
  526.             if (clientp->attrib & fLocked)
  527.                 (void) unlock (clientp);
  528.             paramv[0] = (Ptr) distp;
  529.             paramv[1] = (Ptr) &ca;
  530.             if (whereisit & xSx)
  531.                 paramv[2] = (Ptr) &serverp->dirID;
  532.             else
  533.             {
  534.                 temp = 0;
  535.                 paramv[2] = (Ptr) &temp;
  536.             }
  537.             paramv[3] = (Ptr) &clientp->dirID;
  538.             paramv[4] = (Ptr) &m->ij;
  539.             m->f.state = 3;
  540.             m->todo = todo;
  541.             result = pushCall (matchFolder, paramv);
  542.             if (result != R_CONT)
  543.                 m->f.state = 2;
  544.             else
  545.                 Depth++;
  546.             return result;
  547.         case 3:
  548.             m->f.state = 2;
  549.             Depth--;
  550.             if (!(whereisit & Cxx))
  551.             {
  552.                 clientp = &m->tcn;
  553.                 whereisit |= Cxx;
  554.             }
  555.             if (serverp && (serverp->attrib & fLocked) &&
  556.                     !(Flags&DB_LISTONLY))
  557.                 (void) relock (clientp);
  558.             break;
  559.         }
  560.         break;
  561.  
  562.     default:
  563.         notice (L_NOWHAT, name, nil);
  564.         break;
  565.     } /* end of todo switch */
  566.     if (error == fBsyErr)
  567.         error = 0;                    /* ignore busy file: it may be us
  568.                                      * or we may be running under
  569.                                      * MultiFinder */
  570.     /*
  571.      * Update Finder information, if requested.
  572.      */
  573.     if ((todo == A_UPDATE || todo == A_IGNORE) && error == 0)
  574.         if (ca.copywindow == A_UPDATE || ca.invisible >= A_JUNK
  575.          || ca.locked >= A_JUNK)
  576.             updateFInfo (clientp, serverp, whereisit,
  577.                     ca.copywindow, ca.invisible, ca.locked);
  578.     if (wherereal & xxD)
  579.         m->distp = m->distp->sibp;
  580.     if (wherereal & xSx)
  581.         m->serverp = m->serverp->link;
  582.     if (wherereal & Cxx)
  583.         m->clientp = m->clientp->link;
  584.     if ((error || Quit) && result < R_BACKOUT)
  585.         result = R_BACKOUT;
  586.     return result;
  587.  
  588. cleanexit:
  589.     if (GetHandleSize ((Handle)fh) >= sizeof (lm_t))
  590.     {
  591.         freeList (m->ct);
  592.         freeList (m->st);
  593.     }
  594.     return (popCall (result, nil));
  595. }
  596.  
  597.  
  598.  
  599. /*
  600.  *=========================================================================
  601.  * checkTypes (dp, cp) - find type_node applying to file
  602.  * entry:    dp = ptr to dnode of folder containing file
  603.  *            cp = ptr to catalog node describing file
  604.  * exit:    returns ptr to type_list which applies (possibly nil)
  605.  *=========================================================================
  606.  */
  607.  
  608. tnode_t *
  609. checkTypes (dp, cp)
  610.     dnode_t    *        dp;
  611.     cnode_t *        cp;
  612. {
  613. register OsType        ft;                /* file type */
  614. register OsType        fc;                /* file creator */
  615. register tnode_t *    tp;                /* type_node ptr */
  616.  
  617.     tp = dp->tlistp;
  618.     if (cp == nil || tp == nil)
  619.         return nil;
  620.     ft = cp->in.f.finfo.fdType;
  621.     fc = cp->in.f.finfo.fdCreator;
  622.     if (ft == 0)
  623.         ft = '????';
  624.     if (fc == 0)
  625.         fc = '????';
  626.     for (; tp; tp = tp->morep)
  627.     {
  628.         if (tp->ftype && tp->ftype != ft)
  629.             continue;                /* mismatch on type */
  630.         if (tp->fcreator && tp->fcreator != fc)
  631.             continue;                /* mismatch on creator */
  632.         break;
  633.     }
  634.     return tp;
  635. }
  636.  
  637.  
  638.  
  639.  
  640. /*
  641.  *=========================================================================
  642.  * least (c, s, d) - find alphabetical least of three strings
  643.  * entry:    c = client name string
  644.  *            s = server name string
  645.  *            d = control file name string
  646.  * returns:    bit pattern indicating which of the sources has the least string
  647.  *=========================================================================
  648.  */
  649. short
  650. least (c, s, d)
  651. register StringPtr c, s, d;
  652. {
  653.     switch (RelString (c, s, false, true))
  654.     {
  655.     case -1:                        /* C < S, find lesser of C and D */
  656.         switch (RelString (c, d, false, true))
  657.         {
  658.         case -1:    return Cxx;
  659.         case 0:        return CxD;
  660.         case 1:        return xxD;
  661.         }
  662.     case 0:                            /* C == S, how about D */
  663.         switch (RelString (c, d, false, true))
  664.         {
  665.         case -1:    return CSx;
  666.         case 0:        return CSD;
  667.         case 1:        return xxD;
  668.         }
  669.     case 1:                            /* S < C, find lesser of S and D */
  670.         switch (RelString (s, d, false, true))
  671.         {
  672.         case -1:    return xSx;
  673.         case 0:        return xSD;
  674.         case 1:        return xxD;
  675.         }
  676.     }
  677.     /*NOTREACHED*/
  678.     return 0;
  679. }
  680.  
  681.  
  682.  
  683. /*
  684.  *=========================================================================
  685.  * mergeActions (def, src, dst) - merge default and specific action lists
  686.  * entry:    def = pointer to default action list
  687.  *            src = pointer to specific action list
  688.  *            dst = pointer to list for result of merge
  689.  *            def and dst can be the same without confusion
  690.  *=========================================================================
  691.  */
  692. void
  693. mergeActions (def, src, dst)
  694. register actions_t *    def;
  695. register actions_t *    src;
  696. register actions_t *    dst;
  697. {
  698. register action_t        a;
  699.  
  700.     /*
  701.      * Easy.  Just copy the src to the dst, supplying values from def
  702.      * whereever src action is A_DEFAULT
  703.      */
  704.     dst->ifclient    = (a = src->ifclient  ) != A_DEFAULT ? a: def->ifclient;
  705.     dst->ifserver    = (a = src->ifserver  ) != A_DEFAULT ? a: def->ifserver;
  706.     dst->ifcreate    = (a = src->ifcreate  )    != A_DEFAULT ? a: def->ifcreate;
  707.     dst->ifnewer    = (a = src->ifnewer      ) != A_DEFAULT ? a: def->ifnewer;
  708.     dst->ifolder    = (a = src->ifolder      ) != A_DEFAULT ? a: def->ifolder;
  709.     dst->ifsize        = (a = src->ifsize      ) != A_DEFAULT ? a: def->ifsize;
  710.     dst->otherwise    = (a = src->otherwise ) != A_DEFAULT ? a: def->otherwise;
  711.     dst->copywindow    = (a = src->copywindow)    != A_DEFAULT ? a: def->copywindow;
  712.     dst->invisible    = (a = src->invisible ) != A_DEFAULT ? a: def->invisible;
  713.     dst->locked        = (a = src->locked      ) != A_DEFAULT ? a: def->locked;
  714. }
  715.  
  716.  
  717. /*
  718.  *=========================================================================
  719.  * updateFInfo (cp, sp, where, window, hide) - change Finder info for client
  720.  *            file/folder
  721.  * entry:    cp = pointer to client catalog node
  722.  *            sp = pointer to server catalog node
  723.  *            where = bits for which of cp and sp are valid
  724.  *            window = A_UPDATE to copy server info to client
  725.  *            hide = A_JUNK to make invisible, A_DISCARD to make visible,
  726.  *                    or A_UPDATE to copy server to client
  727.  *            lock = same as hide, but for locked attribute
  728.  * Since this is just a frill, errors are silently ignored
  729.  *=========================================================================
  730.  */
  731. static
  732. void
  733. updateFInfo (cp, sp, where, window, hide, lock)
  734. register cnode_t *        cp;
  735. register cnode_t *        sp;
  736.     short                where;
  737.     action_t            window;
  738.     action_t            hide;
  739.     action_t            lock;
  740. {
  741.     int                    doit;        /* non-zero if need to change client */
  742.     OSErr                error;
  743. register long *            cl, *sl;    /* used to speed compares */
  744.     int                    have;        /* current client visibility or lock */
  745.     Integer                temp;        /* temp to hold client file folder info */
  746.     int                    wantl;        /* lockedness wanted on client */
  747.     int                    wantv;        /* visibility wanted on client */
  748.     CInfoPBRec            ci;
  749.  
  750.     if ((where & Cxx) == 0 || cp == 0)
  751.         return;                        /* if not on client, can't do anything */
  752.     doit = 0;
  753.     /*
  754.      * Check if need to change visibility
  755.      */
  756.     have = cp->in.f.finfo.fdFlags & fInvisible;
  757.     switch (hide)
  758.     {
  759.     case A_JUNK:    wantv = fInvisible; break;
  760.     case A_DISCARD:    wantv = 0; break;
  761.     case A_UPDATE:    if (sp)
  762.                         { wantv = sp->in.f.finfo.fdFlags & fInvisible; break; }
  763.     default:        wantv = have;
  764.     }
  765.     if (have != wantv)
  766.         doit |= 2;
  767.     /*
  768.      * If we should update the window info from the server and the
  769.      * server exists and the info differs between the client and server,
  770.      * then we need to do the update.
  771.      */
  772.     if ((where & xSx) && sp && window == A_UPDATE)
  773.     {
  774.         cp->in.f.finfo.fdFlags &= ~fInvisible;
  775.         temp = sp->in.f.finfo.fdFlags;
  776.         sp->in.f.finfo.fdFlags &= ~fInvisible;
  777.         switch (cp->ctype)
  778.         {
  779.         case C_FILE:
  780.             if (cp->in.f.finfo.fdType        != sp->in.f.finfo.fdType
  781.              || cp->in.f.finfo.fdCreator    != sp->in.f.finfo.fdCreator
  782.              || cp->in.f.finfo.fdFlags        != sp->in.f.finfo.fdFlags
  783.              || *(long *)&cp->in.f.finfo.fdLocation !=
  784.                  *(long *)&sp->in.f.finfo.fdLocation
  785.             )
  786.                 doit = 1;
  787.             break;
  788.         case C_FOLDER:
  789.             cl = (long *)&cp->in.d.dinfo;
  790.             sl = (long *)&sp->in.d.dinfo;
  791.             if (cl[0] != sl[0]            /* frRect top, left */
  792.              || cl[1] != sl[1]            /* frRect bottom, right */
  793.              || cl[2] != sl[2]            /* frFlags & frLocation.v */
  794.              || cl[3] != sl[3]            /* frLocation.h & frView */
  795.              || cp->in.d.frScroll.v != sp->in.d.frScroll.v
  796.              || cp->in.d.frScroll.h != sp->in.d.frScroll.h
  797.              || (cp->in.d.frOChain != 0 && sp->in.d.frOChain == 0)
  798.             )
  799.                 doit = 1;
  800.             break;
  801.         }
  802.     }
  803.     /*
  804.      * Now check lock/unlock
  805.      */
  806.     have = cp->attrib & fLocked;
  807.     switch (lock)
  808.     {
  809.     case A_JUNK:    wantl = fLocked; break;
  810.     case A_DISCARD:    wantl = 0; break;
  811.     case A_UPDATE:    if (sp)
  812.                         { wantl = sp->attrib & fLocked; break; }
  813.     default:        wantl = have;
  814.     }
  815.     if (have != wantl)
  816.         doit |= 4;
  817.     /*
  818.      * If we need to change client's info, get the current values again,
  819.      * change them, and set them back.
  820.      */
  821.     if (doit)
  822.     {
  823.         ZERO (ci);
  824.         ci.hFileInfo.ioVRefNum = ClientVol;
  825.         if (cp->ctype == C_FILE)
  826.         {
  827.             ci.hFileInfo.ioNamePtr = cp->name;
  828.             ci.hFileInfo.ioDirID = cp->parID;
  829.             ci.hFileInfo.ioFDirIndex = 0;
  830.         }
  831.         else
  832.         {
  833.             ci.hFileInfo.ioDirID = cp->dirID;
  834.             ci.hFileInfo.ioFDirIndex = -1;
  835.         }
  836.         error = PBGetCatInfo (&ci, false);
  837.         if (error)
  838.             return;
  839.         if (doit & 1)
  840.         {
  841.             if (cp->ctype == C_FILE)
  842.             {
  843.                 temp = ci.hFileInfo.ioFlFndrInfo.fdFldr;
  844.                 ci.hFileInfo.ioFlFndrInfo = sp->in.f.finfo;
  845.                 ci.hFileInfo.ioFlFndrInfo.fdFldr = temp;
  846.             }
  847.             else
  848.             {
  849.                 ci.dirInfo.ioDrUsrWds = sp->in.d.dinfo;
  850.                 ci.dirInfo.ioDrFndrInfo.frScroll = sp->in.d.frScroll;
  851.                 if (sp->in.d.frOChain == 0)
  852.                     ci.dirInfo.ioDrFndrInfo.frOpenChain = 0;
  853.             }
  854.         }
  855.         ci.hFileInfo.ioFlFndrInfo.fdFlags =
  856.             (ci.hFileInfo.ioFlFndrInfo.fdFlags & ~fInvisible) | wantv;
  857.         ci.hFileInfo.ioFlAttrib =
  858.             (ci.hFileInfo.ioFlAttrib & ~fLocked) | wantl;
  859.         if (Flags & DB_VERBOSE)
  860.             notice (L_FINFO, cp->name);
  861.         if (Flags & DB_LISTONLY)
  862.             return;
  863.         if (cp->ctype == C_FILE)
  864.         {
  865.             ci.hFileInfo.ioDirID = cp->parID;
  866.             ci.hFileInfo.ioFDirIndex = 0;
  867.         }
  868.         error = PBSetCatInfo (&ci, false);
  869.         if (error)
  870.         {
  871.             ClueID = error;
  872.             notice (L_SYS, (SP)"\pUpdateFInfo", (SP)"\pPBSetCatInfo",nil);
  873.         }
  874.         /*
  875.          * Since changing the fLocked bit in the attributes doesn't really
  876.          * lock or unlock anything (Why?), we may need to explicitly lock
  877.          * or relock the file/folder.
  878.          */
  879.         if (doit & 4)
  880.         {
  881.             if (wantl)
  882.                 relock (cp);
  883.             else
  884.                 unlock (cp);
  885.         }
  886.     }
  887. }
  888.  
  889.  
  890. /*
  891.  *=========================================================================
  892.  * updateRoot (dp) - update finder window information for client root folder
  893.  * entry:    dp = pointer to dist_node for client root folder
  894.  * technique:    just set up can call updateFInfo ()
  895.  *=========================================================================
  896.  */
  897. void
  898. updateRoot (dp)
  899.     dnode_t            *dp;
  900. {
  901.     cnode_t            *clientp, *serverp;    /* args for updateFInfo () */
  902.     actions_t        *ra;                /* action list for root */
  903.     file_info_t        *fi;                /* ptr into File_list[] */
  904.  
  905.     /*
  906.      * Exit if nothing to do.
  907.      * Note that most of these exit conditions should never happen!
  908.      */
  909.     if (! dp)
  910.         return;
  911.     fi = &File_list[FL_ROOT];
  912.     if (! fi->f_set)
  913.         return;
  914.     clientp = &fi->f_info;
  915.     fi = &File_list[FL_MAST];
  916.     if (! fi->f_set)
  917.         return;
  918.     serverp = &fi->f_info;
  919.     ra = &dp->actions;
  920.     if (ra->copywindow == A_UPDATE
  921.      || ra->invisible >= A_JUNK
  922.      || ra->locked >= A_JUNK)
  923.     {
  924.         updateFInfo (clientp, serverp, CSD,
  925.                         ra->copywindow, ra->invisible, ra->locked);
  926.     }
  927. }